/*
 * TemplateResource.java
 *
 * Created on September 7, 2007, 11:33 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.atomojo.www.util.script;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.net.URI;
import java.util.Map;
import java.util.logging.Level;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.atomojo.www.util.Identity;
import org.restlet.Client;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.ChallengeResponse;
import org.restlet.data.ChallengeScheme;
import org.restlet.data.CharacterSet;
import org.restlet.data.Cookie;
import org.restlet.data.MediaType;
import org.restlet.data.Method;
import org.restlet.data.Parameter;
import org.restlet.data.Protocol;
import org.restlet.data.Reference;
import org.restlet.data.Status;
import org.restlet.representation.OutputRepresentation;
import org.restlet.representation.Representation;
import org.restlet.resource.ServerResource;

/**
 *
 * @author alex
 */
public class ScriptResource extends ServerResource
{
 
   URI script;
   URI resource;
   MediaType type;
   ScriptCache scriptCache;
   String username;
   String password;
   
   /**
    * Creates a new instance of TemplateResource
    */
   public ScriptResource(ScriptCache scriptCache,URI script,URI resource,MediaType type)
   {
      setNegotiated(false);
      this.script = script;
      this.resource = resource;
      this.type = type;
      this.scriptCache = scriptCache;
      this.username =null;
      this.password = null;
   }
   
   public void setResourceUser(String username, String password)
   {
      this.username = username;
      this.password = password;
   }
   
   public Representation get()
   {
      try {
         final Transformer xform = scriptCache.get(script);
         if (xform==null) {
            getLogger().warning("Script "+script+" was not found.");
            getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
            return null;
         }
         Request remoteRequest = null;
         Client client = null;
         if (resource!=null && !"jar".equals(resource.getScheme())) {
            client = getContext().getClientDispatcher();
            //client = new Client(getContext().createChildContext(),Protocol.valueOf(resource.getScheme()));
            client.getContext().getAttributes().put("hostnameVerifier", org.apache.commons.ssl.HostnameVerifier.DEFAULT);
            remoteRequest = new Request(Method.GET,new Reference(resource.toString()));
            if (username!=null) {
               remoteRequest.setChallengeResponse(new ChallengeResponse(ChallengeScheme.HTTP_BASIC,username,password));
            }
            Cookie cookie = getRequest().getCookies().getFirst("I");
            if (cookie!=null) {
               remoteRequest.getCookies().add(cookie);
            }
         }
         final Response resourceResponse = remoteRequest==null ? null : client.handle(remoteRequest);
         if (resourceResponse==null || resourceResponse.getStatus().isSuccess() && resourceResponse.isEntityAvailable()) {
            getResponse().setStatus(Status.SUCCESS_OK);
            Representation rep = new OutputRepresentation(type) {
               public void write(OutputStream os)
                  throws IOException
               {
                  try {
                     xform.clearParameters();
                     final Identity identity = (Identity)getRequest().getAttributes().get(Identity.IDENTITY_ATTR);
                     if (identity!=null) {
                        xform.setParameter("user.session",identity.getSession());
                        xform.setParameter("user.id",identity.getId());
                        xform.setParameter("user.alias",identity.getAlias());
                        if (identity.getName()!=null) {
                           xform.setParameter("user.name",identity.getName());
                        }
                        if (identity.getEmail()!=null) {
                           xform.setParameter("user.email",identity.getEmail());
                        }
                     }
                     xform.setParameter("request.resource.path",getRequest().getResourceRef().getPath());
                     xform.setParameter("request.resource.authority",getRequest().getResourceRef().getAuthority());
                     xform.setParameter("request.resource.scheme",getRequest().getResourceRef().getScheme());
                     xform.setParameter("request.resource.query",getRequest().getResourceRef().getQuery());
                     xform.setParameter("request.resource.fragment",getRequest().getResourceRef().getFragment());
                     Map<String,Object> attrs = getRequest().getAttributes();
                     for (String name : attrs.keySet()) {
                        Object value = attrs.get(name);
                        if (value instanceof String) {
                           xform.setParameter(name,value);
                        }
                     }
                     for (Parameter param : getContext().getParameters()) {
                        xform.setParameter(param.getName(),param.getValue());
                     }
                     xform.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
                     Reader input = null;
                     try {
                        if (resourceResponse==null) {
                           input = resource==null ? new StringReader("<doc/>") : new InputStreamReader(resource.toURL().openStream());
                        } else {
                           input = resourceResponse.getEntity().getReader();
                        }
                        try {
                           xform.transform(new StreamSource(input,resource==null ? null : resource.toString()),new StreamResult(new OutputStreamWriter(os,"UTF-8")));  
                        } catch (TransformerException ex) {
                           getLogger().log(Level.SEVERE,"Cannot transform feed due to script error.",ex);
                        }
                     } finally {
                        if (input!=null) {
                           input.close();
                        }
                     }
                  } finally {
                     if (resourceResponse!=null) {
                        resourceResponse.getEntity().release();
                     }
                  }
               }
               public void release() {
                  scriptCache.release(script, xform);
               }
            };
            rep.setCharacterSet(CharacterSet.UTF_8);
            return rep;
         } else {
            scriptCache.release(script, xform);
            getResponse().setStatus(resourceResponse.getStatus());
            getResponse().setEntity(resourceResponse.getEntity());
         }
      } catch (IOException ex) {
         getLogger().log(Level.SEVERE,"I/O error while getting script "+script,ex);
         getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
      } catch (TransformerException ex) {
         getLogger().log(Level.SEVERE,"Error while getting script "+script,ex);
         getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
      }
      return null;
   }
   
}
